#ifndef ALMACENAMIENTO_H_
#define ALMACENAMIENTO_H_

#include <string>
#include <list>
#include <fstream>
#include "Bloque.h"
#include "Metadata.h"
#include "RegistroFijo.h"
#include "RegistroVariable.h"


using namespace std;

class EstrategiaAlmacenamiento;

//Clase que almacena un Compuesto en un medio.
class Almacenamiento {
public:
	int almacenar(Registro componente);
	void borrar(int offset, list<string> claves);
	Registro recuperar(int offset, list<string> claves);
	void modificar(Registro componente, int offset);

	virtual int escribir(Componente& componente, int offset) = 0;
	virtual Componente* leer(int offset) = 0;
	virtual void borrarComp(int offset) = 0;
	virtual void imprimir() = 0;

	virtual int buscarEspacioLibre(int) = 0;

	// Textos
	virtual void modificarTexto(Componente&) = 0;
	virtual void borrarTexto(Componente&) = 0;
	virtual Componente* leerTexto(int) = 0;
	virtual void escribirTexto(Componente&) = 0;

	virtual void crearMetadata(char tipo, int tamanio, list<string> tipos, list<bool> claves) = 0;
	virtual void inicializarMetadata(char tipo) = 0;
	Metadata* getMetadata();
	void setMetadata(Metadata*);
	void setExisteMetadata(bool b);
	bool getExisteMetadata();

	virtual Metadata* abrir(char tipo) = 0;//binario o texto
	virtual void cerrar() = 0;
	virtual int eof() = 0;
	int getLongBloque();
	void setLongBloque(int longBloque);
	//estos tienen que ser virtuales?
	virtual int getcantidadBloques() = 0;
	virtual int aumentarComponentesBloques() = 0;
	virtual int getOffsetComienzoDatos() = 0;
	EstrategiaAlmacenamiento* getEstrategiaAlmacenamiento();

protected:
	EstrategiaAlmacenamiento* estrategiaAlm;
	Metadata* metadata;
	bool existeMetadata;
	int longBloque;
};

//Clase que resuelve el algoritmo a aplicar sobre los componentes de datos manejados.
class EstrategiaAlmacenamiento {
public:
	virtual void abrir(Almacenamiento* almacenamiento) = 0; //abre (o crea si no existe) el archivo.
	virtual void cerrar(Almacenamiento* almacenamiento) = 0;
	virtual int
			almacenar(Almacenamiento* almacenamiento, Registro componente) = 0; //guarda los datos y devuelve la direccion.
	virtual void modificar(Almacenamiento* almacenamiento,
			Registro componente, int offset) = 0;
	virtual void borrar(Almacenamiento* almacenamiento, int offset,
			list<string> claves) = 0;
	virtual void borrar(Almacenamiento* almacenamiento, Registro componente) = 0;
	virtual Registro recuperar(Almacenamiento* almacenamiento, int offset,
			list<string> claves) = 0; //devuelve un registro.
	virtual void imprimir(Almacenamiento* almacenamiento) = 0;
protected:
};

//Algoritmo para manejo de datos en texto plano.
class EstrategiaAlmacenamientoTexto: public EstrategiaAlmacenamiento {
public:
	void abrir(Almacenamiento* almacenamiento);
	void cerrar(Almacenamiento* almacenamiento);
	void modificar(Almacenamiento* almacenamiento, Registro componente, int offset);
	void borrar(Almacenamiento* almacenamiento, int offset,list<string> claves);
	void borrar(Almacenamiento* almacenamiento,Registro componente);
	int almacenar(Almacenamiento* almacenamiento, Registro componente); //guarda los datos y devuelve la direccion.
	Registro recuperar(Almacenamiento* almacenamiento, int offset, list<string> claves); //devuelve un componente (en este caso es un registro).
	void imprimir(Almacenamiento* almacenamiento);
private:

};

//Algoritmo para el manejo de datos en Archivo de Registros (si se diferencia el algoritmo para otros tipos de componentes deberá extenderla).
class EstrategiaAlmacenamientoRegistros: public EstrategiaAlmacenamiento {
public:
	void abrir(Almacenamiento* almacenamiento); //abre (o crea si no existe) el archivo.
	void cerrar(Almacenamiento* almacenamiento);
	void modificar(Almacenamiento* almacenamiento, Registro componente,
			int offset);
	void borrar(Almacenamiento* almacenamiento, int offset, list<string> claves);
	void borrar(Almacenamiento* almacenamiento,Registro componente);
	int almacenar(Almacenamiento* almacenamiento, Registro componente); //guarda los datos y devuelve la direccion.
	Registro recuperar(Almacenamiento* almacenamiento, int offset, list<string> claves); //devuelve un registro.
	void imprimir(Almacenamiento* almacenamiento);
private:
};


//Algoritmo para el manejo de datos en Archivo de Bloques con Registros (si se diferencia el algoritmo para otros tipos de componentes deberá extenderla).
class EstrategiaAlmacenamientoBloques: public EstrategiaAlmacenamiento {
public:
	void abrir(Almacenamiento* almacenamiento); //abre (o crea si no existe) el archivo.
	void cerrar(Almacenamiento* almacenamiento);
	void modificar(Almacenamiento* almacenamiento, Registro componente,
			int offset);
	void borrar(Almacenamiento* almacenamiento, int offset, list<string> claves);
	void borrar(Almacenamiento* almacenamiento,Registro componente);
	int almacenar(Almacenamiento* almacenamiento, Registro componente); //guarda los datos y devuelve la direccion.
	Registro recuperar(Almacenamiento* almacenamiento, int offset, list<string> claves); //devuelve un registro.
	void imprimir(Almacenamiento* almacenamiento);

private:

};

#endif /*ALMACENAMIENTO_H_*/
